package qq2564874169.tuaotuao.fx.app.so;


import qq2564874169.tuaotuao.fx.EventDispatcher;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public abstract class AbstractServiceContext implements ServiceContext {
    private Map<String, Object> data = new HashMap<>();
    private static final String beforeDispatcherKey = UUID.randomUUID().toString();
    private static final String afterDispatcherKey = UUID.randomUUID().toString();
    private static final String errorDispatcherKey = UUID.randomUUID().toString();
    private EventDispatcher<ServiceObjectArgs> beforeDispatcher = new EventDispatcher<>(beforeDispatcherKey);
    private EventDispatcher<ServiceObjectArgs> afterDispatcher = new EventDispatcher<>(afterDispatcherKey);
    private EventDispatcher<ServiceObjectErrorArgs> errorDispatcher = new EventDispatcher<>(errorDispatcherKey);

    @Override
    public Map<String, Object> userdata() {
        return data;
    }

    @Override
    public EventDispatcher<ServiceObjectArgs> evAfter() {
        return afterDispatcher;
    }

    @Override
    public EventDispatcher<ServiceObjectArgs> evBefore() {
        return beforeDispatcher;
    }

    @Override
    public EventDispatcher<ServiceObjectErrorArgs> evError() {
        return errorDispatcher;
    }

    protected void onBefore(ServiceObjectArgs e) {
        beforeDispatcher.fire(beforeDispatcherKey, this, e);
    }

    protected void onAfter(ServiceObjectArgs e) {
        afterDispatcher.fire(afterDispatcherKey, this, e);
    }

    protected void onError(ServiceObjectErrorArgs e) {
        errorDispatcher.fire(errorDispatcherKey, this, e);
    }

    @Override
    public void close() {
        if (data != null) {
            data.clear();
        }
        if (beforeDispatcher != null) {
            beforeDispatcher.clear();
        }
        if (afterDispatcher != null) {
            afterDispatcher.clear();
        }
        if (errorDispatcher != null) {
            errorDispatcher.clear();
        }
    }

    protected void executeSo(ServiceObject so, Object state) {
        var e = new ServiceObjectArgs(so, this);
        onBefore(e);
        if (!e.isCancel) {
            try {
                so.onExecute(this, state);
            } catch (Exception ex) {
                var args = new ServiceObjectErrorArgs(so, this, ex);
                onError(args);
                if (!args.isCancel) {
                    throw ex;
                }
            }
        }
        onAfter(e);
    }
}
